#ifndef __NONAME_MEMORY_H__
#define __NONAME_MEMORY_H__


#include <ntifs.h>
#include "nm_undoc.h"


#ifndef NONAME_MEM_TAG
#define NONAME_MEM_TAG 'nonm'
#endif

#ifndef NONAME_MEM_TYPE
#define NONAME_MEM_TYPE PagedPool
#endif

#ifdef NONAME_LIB_USE
#define NONAME_INTER_MEM_TYPE NONAME_MEM_TYPE
#else
#define NONAME_INTER_MEM_TYPE (POOL_TYPE)(NONAME_MEM_TYPE | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE)
#endif

__forceinline  
void* __cdecl operator new(size_t size,  
	POOL_TYPE pool_type,
	ULONG pool_tag)
{  
	ASSERT((pool_type < MaxPoolType) && (0 != size));  
	if(size == 0) {

		return NULL;
	}

	ASSERT(pool_type ==  NonPagedPool ||  
		(KeGetCurrentIrql() < DISPATCH_LEVEL));  

	return ExAllocatePoolWithQuotaTag(pool_type,  
		(ULONG)size,  
		pool_tag);  
} 


__forceinline  
void* __cdecl operator new(size_t size)
{  
	if(size == 0) {

		return NULL;
	}

	ASSERT((KeGetCurrentIrql() < DISPATCH_LEVEL));  

	return ExAllocatePoolWithQuotaTag(NONAME_INTER_MEM_TYPE,  
		(ULONG)size,  
		NONAME_MEM_TAG);  
} 


__forceinline  
void __cdecl operator delete(void* pointer)  
{  
	ASSERT(NULL != pointer);  
	if (NULL != pointer) {

		ExFreePool(pointer);  
	} 
}


__forceinline  
void __cdecl operator delete[](void* pointer)  
{  
	ASSERT(NULL != pointer);
	if (NULL != pointer) {

		ExFreePool(pointer);
	}
} 

__forceinline 
void DisableMaskableInterrupt()
{
	KIRQL Irql = KeRaiseIrqlToSynchLevel();
	UCHAR i;

	for (i = 0; i < KeNumberProcessors; i++) {

		KeSetAffinityThread(KeGetCurrentThread(), 1 << i);
		__asm cli
	}

	KeLowerIrql(Irql);
}

__forceinline 
void EnableMaskableInterrupt()
{
	KIRQL Irql = KeRaiseIrqlToSynchLevel();
	UCHAR i;

	for (i = 0; i < KeNumberProcessors; i++) {
		KeSetAffinityThread(KeGetCurrentThread(), 1 << i);
		__asm sti
	}

	KeLowerIrql(Irql);
}


__forceinline
void EnableWriteProtect()
{
	__asm {
		mov     eax, cr0
		or      eax, 10000h
		mov     cr0, eax
	}

	EnableMaskableInterrupt();
}

__forceinline
void DisableWriteProtect()
{
	DisableMaskableInterrupt();

	__asm {
		mov     eax, cr0
		and     eax, 0fffeffffh
		mov     cr0, eax
	}
}

class kwps {

public:
	kwps() {}
	static void Enable() { EnableWriteProtect(); kwps::m_Switch = TRUE; }
	static void Disable() { DisableWriteProtect(); kwps::m_Switch = FALSE; }
	static BOOLEAN GetSwitch() { return m_Switch; }

private:
	static BOOLEAN m_Switch;

};


__forceinline
void KSleep(INT ms)
{
	LARGE_INTEGER timeOut;
	timeOut.QuadPart = -10000 * ms;
	KeDelayExecutionThread( UserMode, false, &timeOut );
}

__forceinline
BOOLEAN KIsMemVaild(PVOID Addr, ULONG Length)
{
	ULONG Pages;
	ULONG i;
	ULONG Va;
	Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Addr, Length);
	if (Pages > 1000) {
		return FALSE;
	}

	Va = (ULONG)Addr & 0xfffff000;
	for (i = 0; i < Pages; i++) {

		if (!MmIsAddressValid((PVOID)Va)) {
			return FALSE;
		}
		
		Va += 0x1000;
	}

	return TRUE;
}

class klookaside {

#define NM_LOOKASIDE_TAG 'nmls'

public:
	klookaside(ULONG Size, ULONG Tag = NM_LOOKASIDE_TAG, POOL_TYPE PoolType = PagedPool);
	void Release();
	PVOID Allocate();
	VOID Free(PVOID Buffer);
private:
	PPAGED_LOOKASIDE_LIST m_PagedLookasideList;
	PNPAGED_LOOKASIDE_LIST m_NPagedLookasideList;
	POOL_TYPE m_PoolType;
};


#endif